<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // js提供 原型这样一个概念来弥补 普通构造函数的缺点

        function Dog() {
            this.run = function () {
                console.log(this.name + '：跑');
            }
        }

        Dog.prototype.test = function () { }
        // 原型是一个对象，叫prototype，是构造函数的属性--
        // 定义构造函数的时候，js会自动创建prototype属性，是为了存 所有 Dog的实例方法
        // Dog.prototype
        // constructor 指向了自己构造函数


        // d1.test 
        // 使用一个对象的属性或者是方法的时候，会先在自身内存中找，找到就用
        // 找不到 就去 d1.__proto__ 这个属性里面找
        //  d1.__proto__ 执行了 Dog.prototype
        console.log(Dog.prototype);

        let d1 = new Dog()
        let d2 = new Dog()

        // true
        // d1是给实例对象，为什么能用到 Dog原型prototype上的方法
        console.log(d1.test === d2.test);
        console.log(d1.__proto__);

        // true   ， 使用Dog 创建了d1 ，在创建的时候自动给 d1 添加了一个__proto__属性
        // 执行了Dog.prototype
        console.log(d1.__proto__ === Dog.prototype);
        console.log(d2.__proto__ === Dog.prototype);



        /*
            什么原型 
                每一个构造函数（所有函数）都有一个原型prototype属性，这个属性是一个对象，
                    对象存了 构造函数的实例方法。
                每一个对象都有一个 __proto__属性，这个属性执行了自己构造函数的prototype
                
                使用一个对象的属性或者是方法的时候，会先在自身内存中找，找到就用
                    找不到 就去 d1.__proto__ 这个属性里面找
            
        
                 标准的构造函数写法--属性写到 构造函数内部，方法写到构造函数的外部，写到构造函数prototype上


                应用：给构造函数添加方法：使用原型 可以 很容易扩展 构造函数的方法--每年js更新 都会添加一些新的数组方法  

                 构造函数内部做了什么事情？
                    1-创建this
                    2- this.__proto__ = 构造函数.prototype  -添加一个一个__proto__属性，指向自己构造函数的prototype
                    3-return this
        */

        // 标准的构造函数写法--属性写到 构造函数内部，方法写到构造函数的外部，写到构造函数prototype上
        function Person(name) {
            this.name = name;

        }
        Person.prototype.run = function () {
            // 方法被哪个对象调用，this 就是谁
            console.log(this.name + '：run');
        }

        let p1 = new Person('刘建');
        p1.run()


        class Tab {

            // es6里面的方法 就是直接写到了原型上
            test() { }
            //  es6里面的属性写了构造函数创建的那个对象上了
            a = 1;
        }
        let t1 = new Tab()
        console.log(t1);

        console.log(d1);


        // js内置的构造函数--他们的实例方法都是写到了原型上
        let arr = new Array(22, 2223);
        console.log(arr.__proto__);
        console.log(Array.prototype);

        let arr2 = [];
        console.log(arr2.push === arr.push);
        console.log(Array.prototype.push === arr.push);

        // 给已有的构造函数添加方法
        Array.prototype.myPush = function () {
            console.log('myPush');
            console.log(this);
        }

        arr2.myPush();



        // 作业：给arr添加去重方法 
        // arr.uniq()
        // 不改变数组本身
        // arr.myForEach(function(v,i){  log(v,i)})


        // -类 -》  把原来的写选项卡 ---》使用es6类写


    </script>

</body>

</html>